package com.shareach.service.exception;

import java.util.List;
import java.util.Map;
import java.util.Map.Entry;

import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.query.Query;
import org.springframework.data.mongodb.core.query.Update;

import com.benayn.ustyle.Decisional;
import com.benayn.ustyle.Mapper;
import com.benayn.ustyle.Reflecter;
import com.benayn.ustyle.string.Strs;
import com.shareach.common.BizCondition;
import com.shareach.domain.common.Entity;
import com.shareach.util.ReflectionUtil;

public class BaseService<T> {

	protected Update parseDomaintoUpdate2(T domain) {
		final Update u = new Update();
		Reflecter.from(domain).mapper().entryGather().loop(new Decisional<Map.Entry<String, Object>>() {

			@Override
			protected void decision(Entry<String, Object> input) {
				if ("id".equals(input.getKey())) {
					return;
				}
				Object val = input.getValue();
				if (null == val) {
					return;
				}
				if ((null instanceof String) && Strs.isBlank((String) val)) {
					return;
				}
				u.set(input.getKey(), input.getValue());
			}
		});
		return u;
	}

	protected Update parseDomaintoUpdate(T domain) {
		Update update = new Update();
		Map<Object, Object> domainMap = ReflectionUtil.parseDomaintoMap(domain);
		for (Map.Entry<Object, Object> dmain : domainMap.entrySet()) {
			String k = (String) dmain.getKey();
			Object v = dmain.getValue();
			update.set(k, v);
		}
		return update;
	}

	protected Query parseConditionToQuery(BizCondition condition) {
		Map<String, Object> paraMap = condition.getParaMap();
		Query query = new Query();
		// handle query...
		for (Map.Entry<String, Object> entry : paraMap.entrySet()) {
			String key = entry.getKey();
			if (key.equals("updateTime")) {
				continue;
			}
			Object value = entry.getValue();
			if (key.endsWith("date")) {
				String[] date = ((String) value).split(",");
				query.addCriteria(Criteria.where("date").gte(date[0]).lte(date[1]));
			} else {
				query.addCriteria(Criteria.where(entry.getKey()).is(entry.getValue()));
			}
		}
		return query;
	}

	@SuppressWarnings("static-access")
	protected Query parseDomaintoQuery(T domain) {
		final Query query = new Query();
		Map<Object, Object> domainMap = ReflectionUtil.parseDomaintoMap(domain);
		boolean hasId = domainMap.containsKey("_id");
		for (Map.Entry<Object, Object> dmain : domainMap.entrySet()) {

			String k = (String) dmain.getKey();
			if (k.equals("updateTime") || k.equals("fieldExists") || k.equals("fieldNoneExists")
					|| k.equals("propInList")) {
				continue;
			}
			Object v = dmain.getValue();
			query.addCriteria(Criteria.where(k).is(v));
		}

		if (domain instanceof Entity) {
			Entity e = (Entity) domain;

			if (!hasId && null != e.getId()) {
				query.addCriteria(Criteria.where("_id").is(e.getId()));
			}
			// 存在的属性列表
			if (null != e.getFieldExists()) {
				for (String prop : e.getFieldExists()) {
					query.addCriteria(Criteria.where(prop).exists(true));
				}
			}
			// 不存在的属性列表
			if (null != e.getFieldNoneExists()) {
				for (String prop : e.getFieldNoneExists()) {
					query.addCriteria(Criteria.where(prop).exists(false));
				}
			}
			// 某个属性在某个列表内
			if (null != e.getPropInList()) {
				Mapper.from(e.getPropInList()).entryGather().loop(new Decisional<Entry<String, List<Object>>>() {

					@Override
					protected void decision(Entry<String, List<Object>> input) {
						query.addCriteria(Criteria.where(input.getKey()).in(input.getValue()));
					}
				});
			}
			// in operator
			if (null != e.getInOpreatorList()) {
				List<Long> idList = e.getInOpreatorList();
				query.addCriteria(Criteria.where("_id").in(idList));
			}
			// regex
			if (null != e.getRegexMap() && e.getRegexMap().size() > 0) {
				Map<String[], String> regexMap = e.getRegexMap();
				for (Entry<String[], String> entry : regexMap.entrySet()) {
					String[] fields = entry.getKey();
					String value = entry.getValue();
					if (fields.length == 1) {
						query.addCriteria(Criteria.where(fields[0]).regex(value));
					} else {
						Criteria[] criterias = new Criteria[fields.length];
						for (int i = 0; i < fields.length; i++) {
							criterias[i] = new Criteria().where(fields[i]).regex(value);
						}
						query.addCriteria(new Criteria().orOperator(criterias));
					}
				}
			}
		}

		return query;
	}

}
